#include <stdbool.h>
#include <avr/io.h>
#include <stdlib.h>
#include <avr/pgmspace.h>
#include "kernel/uzebox.h"
#include "data/fonts.pic.inc"
#include "data/colorbars.pic.inc" 

//Ball
#define BALL_HEIGHT   1
#define BALL_WIDTH    1
//Paddle
#define PADDLE_WIDTH  1
#define PADDLE_HEIGHT 5
//Tiles
#define BLACK_TILE    0
#define WHITE_TILE    1
#define BALL_TILE     2
//Coordinates
#define MAX_X        38
#define MAX_Y        26
#define MIN_X         2
#define MIN_Y         2
#define CENTER_X     20
#define CENTER_Y     14
//Ball directions
#define WEST          0
#define EAST          1
#define NORTH_EAST    2
#define NORTH_WEST    3
#define SOUTH_EAST    4
#define SOUTH_WEST    5

void drawBall(int x,int y, int color);
void movePaddle(int dir, bool left);
void moveBall();
void drawPaddle(int x, int y, int color);

const char tiles[] PROGMEM ={
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	//tile #0 

 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,	//tile #1

0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,	//tile #2 Ball
};

unsigned int leftPaddlePos  = 12;
unsigned int rightPaddlePos = 12;
unsigned int ballXPos       = CENTER_X;
unsigned int ballYPos       = CENTER_Y;
unsigned int ballDir        = EAST;

int main(){
	unsigned int joy1;
	unsigned int joy2;	
	
	ClearVram();
	SetTileTable(tiles);

	//Paint Top Wall
	Fill(MIN_X,MIN_Y,MAX_X-1,1,1);
	//Paint Bottom Wall	
	Fill(MIN_X,MAX_Y,MAX_X-1,1,1);
	//Draw initial right paddle
	drawPaddle(MAX_X,rightPaddlePos, WHITE_TILE);	
	//Draw initial left paddle
	drawPaddle(MIN_X,leftPaddlePos, WHITE_TILE);		
	//Draw initial ball
	drawBall(ballXPos,ballYPos, WHITE_TILE);

	while(1) {
		//Slow down a bit
		WaitVsync(1);
		
		//Player 1 movement
		joy1 = ReadJoypad(0);
		if(joy1&0xff) {
			if(joy1&BTN_DOWN && rightPaddlePos < (MAX_Y-PADDLE_HEIGHT)) {
				movePaddle(1,0);
			} else if(joy1&BTN_UP && rightPaddlePos > (MIN_Y+1)) {
				movePaddle(-1,0);			
			}
		}

		//Player 2 movement
		//joy2 = ReadJoypad(1);
		if(joy2&0xff) {
			if(joy2&BTN_DOWN && leftPaddlePos < (MAX_Y-PADDLE_HEIGHT)) {
				movePaddle(1,1);
			} else if(joy2&BTN_UP && leftPaddlePos > (MIN_Y+1)) {
				movePaddle(-1,1);			
			}
		}
		
		//Move the ball
 		moveBall();		
	}
} 

void moveBall() {
	//Fill in current ball position
	drawBall(ballXPos,ballYPos,BLACK_TILE);
	//Check if ball is in bounds
	if(ballXPos >= MAX_X) {
		ballXPos = CENTER_X;
		ballYPos = CENTER_Y;
		ballDir  = WEST;
	} else if (ballXPos <= MIN_X) {
		ballXPos = CENTER_X;		
		ballYPos = CENTER_Y;		
		ballDir  = WEST;
	//Check if ball has collided with a paddle
	} else if(ballXPos == MAX_X-1 && (ballYPos == rightPaddlePos+ 2)) {
		ballDir = EAST;
	} else if(ballXPos == MIN_X+1 && (ballYPos == leftPaddlePos + 2)) {
		ballDir = WEST;
	} else if(ballXPos == MIN_X+1 && (ballYPos >= leftPaddlePos  && ballYPos <= leftPaddlePos + 1)) {
		ballDir = NORTH_WEST;
	} else if(ballXPos == MAX_X-1 && (ballYPos >= rightPaddlePos && ballYPos <= rightPaddlePos + 1)) {
		ballDir = NORTH_EAST;
	} else if(ballXPos == MAX_X-1 && (ballYPos <= (rightPaddlePos+PADDLE_HEIGHT) && 
									  ballYPos >= rightPaddlePos + PADDLE_HEIGHT-2)) {
		ballDir = SOUTH_EAST;
	} else if(ballXPos == MIN_X+1 && (ballYPos <= (leftPaddlePos+PADDLE_HEIGHT)  && 
									  ballYPos >= leftPaddlePos + PADDLE_HEIGHT-2)) {
		ballDir = SOUTH_WEST;
	//Check if ball has collided with a wall
	} else if(ballYPos <= MIN_Y+1 && ballDir == NORTH_EAST) {
		ballDir = SOUTH_EAST;
	} else if(ballYPos <= MIN_Y+1 && ballDir == NORTH_WEST) {
		ballDir = SOUTH_WEST;	
	} else if(ballYPos >= MAX_Y-1 && ballDir == SOUTH_WEST) {
		ballDir = NORTH_WEST;	
	} else if(ballYPos >= MAX_Y-1 && ballDir == SOUTH_EAST) {
		ballDir = NORTH_EAST;
	}
    
	//Move ball in the desired direction
	switch(ballDir) {
		case WEST:		 drawBall(++ballXPos,   ballYPos, BALL_TILE); break;
		case EAST:		 drawBall(--ballXPos,   ballYPos, BALL_TILE); break;
		case NORTH_WEST: drawBall(++ballXPos, --ballYPos, BALL_TILE); break;
		case SOUTH_WEST: drawBall(++ballXPos, ++ballYPos, BALL_TILE); break;
		case NORTH_EAST: drawBall(--ballXPos, --ballYPos, BALL_TILE); break;
		case SOUTH_EAST: drawBall(--ballXPos, ++ballYPos, BALL_TILE); break;
		default: break;
	}
}

void drawBall(int x, int y, int color) {
	Fill(x,y,BALL_WIDTH,BALL_HEIGHT,color);		
}

void movePaddle(int dir, bool left) {
	if(left) {
		drawPaddle(MIN_X,leftPaddlePos, BLACK_TILE);
		leftPaddlePos += dir;
		drawPaddle(MIN_X,leftPaddlePos, WHITE_TILE);
	} else {	
		drawPaddle(MAX_X,rightPaddlePos, BLACK_TILE);
		rightPaddlePos += dir;
		drawPaddle(MAX_X,rightPaddlePos, WHITE_TILE);
	}
}

void drawPaddle(int x, int y, int color) {
	Fill(x,y,PADDLE_WIDTH,PADDLE_HEIGHT,color);	
}